package danceDoll;

import bvh.BVHBone;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import com.jme3.math.Vector3f;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Records the current animation and transitions and save them in a new BVH-File
 * @author Sebastian Schwaemmle
 */

public class Record {

    public Initialize init;
    private AnimationControl animControl;
    private StringBuilder newBVH = new StringBuilder();
    private Boolean recording = false;
    private int oldFrame, cFrames = 0;
    private float frameTime;
    private String URL, name, newBVHString, hierarchy;

    public Record(AnimationControl animControl, Initialize init) throws FileNotFoundException, IOException {
        this.animControl = animControl;
        this.init = init;
    }

    public Record() {
    }

    /**
     * Starts the recording, sets values and creates hierarchy
     */
    public void startRec() {
        if (this.animControl.getCurrentAnimation().chkBVH()) {
            this.newBVH = new StringBuilder();
            this.newBVHString = "";
            this.recording = true;
            this.oldFrame = -1;
            this.cFrames = 1;
            this.frameTime = this.animControl.getCurrentAnimation().animation.getFrameTime();

            this.hierarchy = "HIERARCHY\n";
            
            // Create the Hirachy-Part from the BVH
            createHierachy(this.animControl.getCurrentAnimation().animation.getHierarchy(), "");

            // Catch first Frame from the current Animation
            traverseBVH(this.animControl.getCurrentAnimation().animation.getHierarchy(), true);
            this.newBVH.append(this.newBVH.substring(0, this.newBVH.length() - 1) + "\n");
        }
    }

    /**
     * Stops the recording and calls the Method to save the recorded Data
     */
    public void stopRec() {
        recording = false;

        // Add Aditional Information fFrames and FrameTime
        this.newBVHString = this.hierarchy + "MOTION\nFrames: " + this.cFrames + "\nFrame Time: " + this.frameTime + "\n" + this.newBVH;
    }

    /**
     * tranverses the BVH-skeleton and saves the offset and channels
     * @param bvhBone the bone to create the channel from
     * @param tabs tab-stops for formatting
     */
    public void createHierachy(BVHBone bvhBone, String tabs) {
        if (bvhBone != null) {
            if (bvhBone.getName().equals("Site")) {
                this.hierarchy += tabs + "End Site";
            } else if (bvhBone.getName().equals("Hip")) {
                this.hierarchy += "ROOT Hip";
            } else {
                this.hierarchy += tabs + "JOINT " + bvhBone.getName();
            }
            this.hierarchy += "\n" + tabs + "{\n";

            Vector3f offset = bvhBone.getOffset();
            if (offset != null) {
                this.hierarchy += tabs + "\tOFFSET " + offset.x + " " + offset.y + " " + offset.z + "\n";
            }

            if (bvhBone.getChannels() != null) {
                int cChannels = bvhBone.getChannels().size();
                this.hierarchy += tabs + "\tCHANNELS " + cChannels;
                if (cChannels == 3) {
                    this.hierarchy += " Xrotation Yrotation Zrotation\n";
                } else {
                    this.hierarchy += " Xposition Yposition Zposition Xrotation Yrotation Zrotation \n";
                }
            }

            List<BVHBone> children = bvhBone.getChildren();
            if (children != null) {
                for (BVHBone b : children) {
                    createHierachy(b, tabs + "\t");
                }
            }
            this.hierarchy += tabs + "}\n";
        }
    }
    
    /**
     * Start the Recording from the current animation, when method "startRec" was called
     */
    public void recFrames() {
        if (this.recording && this.animControl.getCurrentAnimation().chkBVH()) {
            int currentFrame = this.animControl.getCurrentFrame();
            if (this.oldFrame != currentFrame) {

                traverseBVH(this.animControl.getCurrentAnimation().animation.getHierarchy(), false);
                this.newBVH.substring(0, this.newBVH.length() - 1);
                this.newBVH.append("\n");
                this.oldFrame = currentFrame;
                this.cFrames++;
                init.getGuiController().updateFrames();
                
                if (cFrames % 25 == 0){
                    init.getGuiController().recBlink();
                }  
            }
        }
    }

    /**
     * Reads every Bone from the BVH-Animation-File, and writes the Values to the returning String
     * @param bvhBone 
     */
    public void traverseBVH(BVHBone bvhBone, Boolean firstFrame) {
        if (bvhBone != null) {
            if (bvhBone.getChannels() != null) {
                for (int j = 0; j < bvhBone.getChannels().size(); j++) {
                    if (firstFrame) {
                        this.newBVH.append(bvhBone.getChannels().get(j).getValues().get(0) + " ");
                    } else {
                        this.newBVH.append(bvhBone.getChannels().get(j).getValues().get(this.animControl.getCurrentFrame()) + " ");
                    }
                }
            }

            List<BVHBone> children = bvhBone.getChildren();
            if (children != null) {
                for (BVHBone b : children) {
                    traverseBVH(b, firstFrame);
                }
            }
        }
    }

    /**
     * Saves the new BVH-File to the givn path
     */
    public void save() {
        if (URL != null) {

            File file = new File(URL);
            if (!file.exists()) {
                try {
                    file.createNewFile();
                } catch (IOException ex) {
                    Logger.getLogger(Record.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

            try {
                FileWriter writer = new FileWriter(file);
                BufferedWriter output = new BufferedWriter(writer);
                output.write(this.newBVHString);
                output.close();
                writer.close();  
            } catch (IOException e) {
                System.out.println("Schreibfehler: " + e);
            }
        }
    }

    /**
     * Set the URL where the recorded material is set to
     * @param url URL to save to
     */
    public void setURL(String url) {
        URL = url;
    }

    /**
     * Returns the URL where the recordings are saved
     * @return URL from the current saved BVH-File
     */
    public String getURL() {
        return URL;
    }
    
    /**
     * Sets the name from the file where the recorded animation shuld be saved
     * @param name Name of the file
     */
    public void setName(String name){
        this.name =name;
    }
    
    /**
     * Returns the name from the file the recorded animation was saved to
     * @return name from the file
     */
    public String getName(){
        return name;
    }
    /**
     * Returns the current Frame from the recording
     * @return current Frame from the Recording
     */
    public int getCurrentFrame() {
        return this.cFrames;
    }
    
    /**
     * Returns the Frame Time from the animataion when the record-button was pressed
     * @return Frame Time
     */
    public float getFrameTime() {
        if(this.animControl.getCurrentAnimation() != null)
            return this.frameTime;
        return 0;
    }
}
